/**
  ******************************************************************************
  * @file    can.c
  * @author  Dajin Li
  * @version V0.0.1
  * @date    08-08-2015 
  * @brief    This file contains CAN specific functions.
  *          
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; KION(SZ) R&D Center
  *
  * Licensed under KION, (the "License");
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/

#include "stm32f10x.h"
#include "stm32f10x_can.h"
#include "global.h"
#include "CAN.h"
#include "can_open.h"
#include "var_tbl.h"
#include "task.h"
#include "Instrument.h"
#include "lcd.h"
#include "misc.h"
#include "cromo.h"
#include "bis.h"

/* Local variables ------------------------------------------------------------------*/

static s16 inhibit_restart_bus_CAN = 0;     // Inhibit auto-restart CAN bus after bus-off

/* Global variables ------------------------------------------------------------------*/

u16 can_node_id = 4;
s16 can_baud_rate = CAN_500KBAUD;
s16 can_bus_on = 0;                 // CAN Bus Status (0=off, non-0=on)
s16 can_error_status = 0;           // Error Status: Bit0=EWRN, Bit1=BOFF
s16 working_can_slave_id = CAN_SLAVE_ID_DEF;
s16 working_can_master_id = CAN_MASTER_ID_DEF;

CanRxMsg CANopenRxMsgBuf[CANOPEN_RX_MSG_BUF] = {0};
u8 CANopen_rx_buf_head;
u8 CANopen_rx_buf_tail;
u32 stay_in_boot_time_start; 
static struct cromo crc_me;
cromo_callback_t crc_function;
s16 crc_rv; 
static s32 flashing_time = 0;
static s32 receiving_msg_time = 0;

u16 flashing_timeout = 0;
/* Local functions ------------------------------------------------------------------*/
cromo_cks_t cks_function(void * const start, U32 len, enum cromo_func_status status );

static void check_busoff(void);
/**
  * @brief  Configures the NVIC for CAN.
  * @param  None
  * @retval None
  */
void CANopen_NVIC_Config(void)
{
    NVIC_InitTypeDef  NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

    NVIC_InitStructure.NVIC_IRQChannel = CANOPEN_CAN_RX_IRQ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief    Configure CAN. Use CAN2
* @param    none
* @note     none
* @retval   none
*/
void CAN_Config(void)
{
    u8 i = 0;
    u8 filter_number = 0;

    GPIO_InitTypeDef GPIO_InitStructure = {0};
    CAN_FilterInitTypeDef CAN_FilterInitStructure = {0};
    CAN_InitTypeDef CAN_InitStructure = {0};

    if(can_bus_on)
    {
        CAN_Enabled = 0;
        can_bus_on = 0;
    }

    /* Configure CAN pin: RX */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CANOPEN_RX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIO_CANOPEN, &GPIO_InitStructure);

    /* Configure CAN pin: TX */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CANOPEN_TX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIO_CANOPEN, &GPIO_InitStructure);

    /* CAN register init */
    CAN_DeInit(CANOPEN_CAN);
    CAN_StructInit(&CAN_InitStructure);

    /* CAN cell init */
    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = ENABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;



    CAN_InitStructure.CAN_Prescaler = 4;

    

    CAN_Init(CANOPEN_CAN, &CAN_InitStructure);
    //CAN_Set_Baudrate(can_baud_rate);

    for(i = filter_number; i < FILTER_NUMBER_DEF; i++)
    {
        /* CAN filter init */
        CAN_FilterInitStructure.CAN_FilterNumber = i;
        CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
        CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
        CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
        CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
        CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
        CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
        CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CANOPEN_CAN_FIFO;
        CAN_FilterInitStructure.CAN_FilterActivation = DISABLE;
        CAN_FilterInit(&CAN_FilterInitStructure);
    }
    
    working_can_master_id = (can_node_id >> 5) & 0x03;
    working_can_slave_id = can_node_id  & 0x1f;
    canopen_init();


    CANopen_NVIC_Config();

    /* Enable FIFO 1 message pending Interrupt */
    CAN_ITConfig(CANOPEN_CAN, CAN_IT_FMP0, ENABLE);
    CAN_Enabled = 1;
    can_bus_on = 1;
    CANopen_rx_buf_head = 0;
    CANopen_rx_buf_tail = 0;
}
/**
* @brief    set baud rate.
* @param    rate:can baud rate
* @note     none
* @retval   none
*/
u8 CAN_Set_Baudrate(u8 rate)
{
    u8 InitStatus = CAN_InitStatus_Failed;
    u32 wait_ack = 0x00000000;
    CAN_InitTypeDef  CAN_InitStructure = {0};

   //FOR SYSCLK=72M,PCLK1=36M SETTING
   //CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
   //CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
   //CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;
   //FOR SYSCLK = PCLK1 = 48M SETTING
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;


    /*
    BaudRate = 1/NominalBitTime
    NominalBitTime=tq+tbs1+tbs2
    */
    if(rate == CAN_250KBAUD)
    {
        CAN_InitStructure.CAN_Prescaler = 6;
    }
    else if(rate == CAN_500KBAUD)
    {
        CAN_InitStructure.CAN_Prescaler = 4;
    }
    else//125KABUD
    {
        CAN_InitStructure.CAN_Prescaler = 12;
    }
    
    /* Request initialisation */
    CANOPEN_CAN->MCR |= CAN_MCR_INRQ ;

    /* Wait the acknowledge */
    while (((CANOPEN_CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT))
    {
        wait_ack++;
    }

    /* Check acknowledge */
    if ((CANOPEN_CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK)
    {
        InitStatus = CAN_InitStatus_Failed;
    }
    else 
    {
        CANOPEN_CAN->BTR |= ((u32)CAN_InitStructure.CAN_SJW << 24) | ((u32)CAN_InitStructure.CAN_BS1 << 16) |
                     ((u32)CAN_InitStructure.CAN_BS2 << 20) | ((u32)CAN_InitStructure.CAN_Prescaler - 1);   
        /* Request leave initialisation */
        CANOPEN_CAN->MCR &= ~(u32)CAN_MCR_INRQ;
        wait_ack = 0;
        while (((CANOPEN_CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT))
        {
            wait_ack++;
        }
        if ((CANOPEN_CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)
        {
            InitStatus = CAN_InitStatus_Failed;
        }
        else
        {
            InitStatus = CAN_InitStatus_Success ;
        }
    }
    return InitStatus;
}
/**
* @brief    make cob id.
* @param    type:can message type
* @param    master_id:master id
* @param    slave_id:slave id
* @note     none
* @retval   none
*/
u16 make_cob_id(u16 type, u16 master_id, u16 slave_id)
{
    return( (type << 7) | (master_id << 5) | (slave_id) );
}

/**
* @brief    check can bus is on or off
* @param    none
* @note     none
* @retval   none
*/
static void check_busoff(void)
{
    static s16 busoff_timeout = 0;
    can_error_status = CANOPEN_CAN->ESR >> 4;
    if(CAN_GetFlagStatus(CANOPEN_CAN,CAN_FLAG_EPV))
    {  
        if(busoff_timeout < CANOPEN_FAULT_DELAY)
        {
            busoff_timeout++ ;
        }
        if (inhibit_restart_bus_CAN == 0) 
        {
            CAN_Config();
        }
    }
    else if(CAN_GetLSBTransmitErrorCounter(CANOPEN_CAN) == 0)
    {
        if(busoff_timeout > 0)
        {
            busoff_timeout--;
        }
    }

}
void KWP_send_pending_msg(void)
{
    sdo_data[0] = 3;
    sdo_data[1] = KWP_FAIL;
    sdo_data[2] = 0x31;
    sdo_data[3] = 0x78;
    sdo_data[4] = 0;
    sdo_data[5] = 0;
    sdo_data[6] = 0;
    sdo_data[7] = 0;    
    send_kwp_response();
}

/**
* @brief    can task main entry
* @param    none
* @note     none
* @retval   none
*/
void CAN_task(void)
{
    u32 crc_32;
    struct bis *app_bis = (struct bis *)(*(u32 *)AppBISAddress);
    stay_in_boot_time_start = osTick; 
    
    if((app_bis != 0) && (stay_for_ever == 0))   // app bis is not null and doen't need to stay in boot
    {
        if((((u32)app_bis % 4) != 0) || ((u32)app_bis < ApplicationSwAddress) || ((u32)app_bis > ApplicationEndAddress)) // test bis address range
        {
            LCD_init();             //initialize monochrome 240x320 display
            Display_H24_Str((u8 *)"APP CRC ERROR", 3, 12, 0);
            stay_for_ever = 1;
        }


        if(stay_for_ever == 0)
        {
            CRC_ResetDR();
            crc_32 = CRC_CalcBlockCRC((u32 *)app_bis, BIS_LEN); // calculat boot software crc
            if(crc_32 != app_bis->bis_checksum)
            {
                LCD_init();
                Display_H24_Str((u8 *)"APP CRC ERROR", 3, 12, 0);
                stay_for_ever = 1;
            }  
            crc_rv = 0;
            cromo_initialize( &crc_me, app_bis->checksum_value, (U32 *)(app_bis->checksum_start), app_bis->checksum_len, cks_function );
        }
    }

    
    // Tasks must run in an infinite loop:
    while (TRUE)
    {
        check_busoff();
        // check 1Kbyte of Flash here
        if(stay_for_ever == 0)  // app bis is not null and doen't need to stay in boot
        {
            if(crc_rv >= 0)
            {
                crc_rv = cromo_process(&crc_me, 0x1000);
            }
            if(crc_rv < 0)
            {   
                LCD_init();
                Display_H24_Str((u8 *)"APP CRC ERROR", 3, 12, 0);
                stay_for_ever = 1;
            }
        }
         
        if(CAN_Enabled!= 0)
        {
            flashing_time = osTick;
            Multi_msg_send();
            while(CANopen_rx_buf_head != CANopen_rx_buf_tail)
            {
                receiving_msg_time = osTick;
                process_msg(&CANopenRxMsgBuf[CANopen_rx_buf_tail]);
                CANopen_rx_buf_tail++;
                CANopen_rx_buf_tail &= (CANOPEN_RX_MSG_BUF - 1);
            }


            if(stay_for_ever == 1)
            {
                if(((flashing_time - receiving_msg_time) > 3000) && (receiving_msg_time != 0))
                {
                    receiving_msg_time = 0;
                    LCD_clear();
                    Display_H24_Str((u8 *)"TIME OUT", 3, 30, 0);
                }
            }
            
            if((stay_for_ever == 0) && (cromo_status(&crc_me)) && (flashing_time - stay_in_boot_time_start >= stay_in_boot_time))
            {
                break;
            }           
        }   
    }  // end while infinite loop
}  // end CAN_task()

cromo_cks_t cks_function(void * const start, U32 len, enum cromo_func_status status )
{
    U32 crc_result;
    if(status == cromo_func_status_first)
    {
        CRC_ResetDR();
        crc_result = CRC_CalcBlockCRC((u32 *)start, len); // app sw crc
    }
    else
    {
        crc_result = CRC_CalcBlockCRC((u32 *)start, len); // app sw crc
    }
    return crc_result;
    
}



